package com.ht.api.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.ht.api.constant.CacheConstants;
import com.ht.api.db.Db;
import com.ht.api.db.Entity;
import com.ht.api.db.util.RedisUtil;
import com.ht.api.util.IpUtils;
import com.ht.api.util.UserUtil;

import cn.hutool.json.JSONObject;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;

@Aspect
@Component
@Slf4j
public class CallControllerMonitorAspect {

    // 切入点：匹配CallController中所有public方法
    @Pointcut("execution(public * com.ht.api.controller.CallController.*(..))")
    public void callControllerMethods() {}

    @AfterThrowing(pointcut = "callControllerMethods()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            
            HttpServletRequest request = attributes.getRequest();
            
            // 获取方法参数
            Object[] args = joinPoint.getArgs();
            String bodyParam = "";
            
            // 解析参数
            for (Object arg : args) {
                if (arg instanceof JSONObject) {
                    bodyParam = ((JSONObject) arg).toString();
                }
            }
            
            // 获取接口key
            String path = request.getRequestURL().toString();
            int index = path.lastIndexOf("/");
            String keyParam = path.substring(index + 1);
            
            // 构建日志实体
            Entity callErrorLog = Entity.create("call_error_log");
            callErrorLog.set("call_id", getCallId(keyParam));
            callErrorLog.set("path", path);
            callErrorLog.set("param", bodyParam);
            callErrorLog.set("ipaddr", IpUtils.getHostIp());
            callErrorLog.set("login_user", UserUtil.getLoginUser().getId());
            callErrorLog.set("error_msg", ex.getMessage());
            callErrorLog.set("stack_trace", getStackTraceAsString(ex));
            Db.insert(callErrorLog);
            log.warn("[call接口异常]已写入call_error_log表。path: {} ,param: {} ,err: {}",
            		path, bodyParam, ex.getMessage());
        } catch (Exception e) {
            log.error("[call接口异常]：{}", e.getMessage(), e);
        }
    }
    
    private String getStackTraceAsString(Throwable throwable) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : throwable.getStackTrace()) {
            sb.append(element.toString());
            sb.append("\n");
        }
        return sb.toString();
    }

	/**
	 * 从缓存中获取callId
	 * @param key call表数据对应的key值
	 * @return
	 */
	private String getCallId(String key) {
		Entity bean = RedisUtil.get(CacheConstants.KEY_CALL + key);
		if (bean == null || bean.isEmpty()) {
			return null;
		}
		return bean.getMainId();
	}
}
